package cmpe451.group7.ourcity.service.impl;

import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.List;

import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;

import cmpe451.group7.ourcity.dao.TagDAO;
import cmpe451.group7.ourcity.dao.UserDAO;
import cmpe451.group7.ourcity.entity.Comment;
import cmpe451.group7.ourcity.entity.Tag;
import cmpe451.group7.ourcity.entity.User;
import cmpe451.group7.ourcity.service.UserService;
import cmpe451.group7.ourcity.util.Logger;
import cmpe451.group7.ourcity.util.PasswordHash;
import cmpe451.group7.ourcity.util.TagToName;

@Service("userService")
public class UserServiceImpl implements UserService, Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private UserDAO userDAO;

	@Autowired
	private TagDAO tagDAO;

	public UserServiceImpl() {
	}

	/**
	 * Authenticate a user with the given username and password.
	 * 
	 * @param email
	 * @param password
	 * @return null if there is an authentication error, a User object otherwise
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 */

	@Transactional
	public User authenticate(String email, String password)
			throws NoSuchAlgorithmException, InvalidKeySpecException {

		User user = userDAO.findUserByEmail(email);

		return authenticateHelper(user, password);
	}

	@Transactional
	public User authenticate(long userID, String password)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		User user = userDAO.findByID(userID);

		return authenticateHelper(user, password);
	}

	private User authenticateHelper(User user, String password)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		if (user != null) {
			// User's password is stored in hashed form in the database.
			String hashedUserPassword = user.getPassword();
			boolean match = PasswordHash.validatePassword(password,
					hashedUserPassword);

			if (match) {
				Hibernate.initialize(user.getLikedPlace());
				return user;
			} else {
				Logger.log("Wrong password entry");
				return null;
			}
		} else {
			Logger.log("Wrong email entry");
			return null;
		}
	}

	@Override
	@Transactional
	public void updateUserInfo(String userInfoText, User user) {
		user.setUserInfo(userInfoText);
		userDAO.update(user);
	}

	@Override
	@Transactional
	public void updateAboutMe(String aboutMe, User user) {
		user.setAboutMe(aboutMe);
		userDAO.update(user);
	}

	@Override
	@Transactional
	public User fullyLoadUser(long homeUserID) {
		User user = userDAO.findByID(homeUserID);
		Hibernate.initialize(user.getLikedPlace());
		Hibernate.initialize(user.getBadges());

		return user;
	}

	@Override
	@Transactional
	public List<String> getCommentTagsofUser(User user) {
		List<Tag> commentTags = tagDAO.getTagsofUser(user);
		List<String> commentTagNames = Lists.transform(commentTags,
				TagToName.INSTANCE);
		return commentTagNames;
	}

	@Override
	@Transactional
	public List<Comment> getCommentsofUser(User user) {
		return userDAO.getCommentsofUser(user);
	}

	@Override
	public void updateUser(User user) {
		userDAO.update(user);
	}

}
